﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.ComponentModel.DataAnnotations.Schema;
using Model;
using System.Data.Entity.ModelConfiguration;

namespace DataAccess
{
    public class PortalContext : DbContext
    {
        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }

        public DbSet<User> Users { get; set; }
        public DbSet<UserProfile> UserProfiles { get; set; }

        public DbSet<Manager> Managers { get; set; }
        public DbSet<Role> Roles { get; set; }

        public DbSet<Classify> Classify { get; set; }

        /// <summary>
        /// 在静态构造函数中，设置数据库的初始化方式
        /// </summary>
        static PortalContext()
        {
            #region Entity Framework CodeFirst数据库连接

            //Entity Framework通过Database.SetInitializer来指定需要的数据库初始化方式
            //可以指定的数据库初始化方式一共3种
            //Database.SetInitializer<PortalContext>(null);
            //Database.SetInitializer(new DropCreateDatabaseIfModelChanges<PortalContext>());

            //1:CreateDatabaseIfNotExists是Database.SetInitializer指定数据库的默认方式，
            //用于当数据库不存在时，自动创建数据库。由于该方式是默认方式，
            //所以可以不需要任何代码进行指定，当然也可以使用代码来明确的指定

            //自动迁移
            //Database.SetInitializer(new CreateDatabaseIfNotExists<PortalContext>());

            //2:DropCreateDatabaseWhenModelChanges用于当数据模型发生改变时，
            //先删除原数据库，后创建新的数据库。
            //Database.SetInitializer(new DropCreateDatabaseIfModelChanges<PortalContext>());

            //3:DropCreateDatabaseAlways用于每次均先删除原数据库再创建新的数据库，
            //不管数据模型是否发生改变。
            //Database.SetInitializer(new DropCreateDatabaseAlways<PortalContext>());
            #endregion
        }
        /// <summary>
        /// 在构造函数中，设置App.config的connectionString
        /// </summary>
        public PortalContext() : base("name=PortalContext")
        {
            #region Entity Framework CodeFirst数据库连接
            //禁用延时加载的原因：
            //在Entity Framework通过延迟加载去读取关联记录时，
            //可能执行过多的SQL语句，与实际所预想的不一致，从而影响代码的执行效率。


            //延时加载：禁用延时加载
            this.Configuration.LazyLoadingEnabled = false;

            #endregion
        }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            #region 冗余代码
            //modelBuilder.Entity<Category>()
            //   .HasMany(t => t.Products)
            //   .WithRequired(t => t.Category)
            //   .HasForeignKey(d => d.CatID);
            //modelBuilder.Entity<Product>()
            //    .HasRequired(t => t.Category)
            //    .WithMany(t => t.Products)
            //    .HasForeignKey(d => d.CatID);
            //base.OnModelCreating(modelBuilder);
            #endregion

            //一对多关系
            modelBuilder.Configurations.Add(new CategoryMap());
            modelBuilder.Configurations.Add(new ProductMap());

            //一对一关系
            modelBuilder.Configurations.Add(new UserProfileMap());
            modelBuilder.Configurations.Add(new UserMap());

            //多对多关系
            modelBuilder.Configurations.Add(new ManagerMap());
            modelBuilder.Configurations.Add(new RoleMap());

            //一对多自反关系
            modelBuilder.Configurations.Add(new ClassifyMap());

            #region Entity Framework CodeFirst数据库连接
            //禁用关系数据的级联删除:
            //1：禁用一对多级联关系
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
            //2：禁用多对的关系数据级联删除
            modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

            //禁用表名复数形式
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            #endregion
        }
    }

    /// <summary>
    /// 定义约束类(Category)
    /// </summary>
    public class CategoryMap : EntityTypeConfiguration<Category>
    {
        /// <summary>
        /// 构造函数中处理（属性约束）
        /// </summary>
        public CategoryMap()
        {
            //配置一对多关系（通过导航属性Products），

            this.HasMany(t => t.Products)
            .WithRequired(t => t.Category)
            .HasForeignKey(d => d.CatID);
        }
    }

    /// <summary>
    /// 定义约束类 （Product）
    /// </summary>
    public class ProductMap : EntityTypeConfiguration<Product>
    {
        /// <summary>
        /// 构造函数中处理 （属性约束）
        /// </summary>
        public ProductMap()
        {
            this.HasRequired(t => t.Category)
                        .WithMany(t => t.Products)
                         .HasForeignKey(d => d.CatID);
        }
    }


    /// <summary>
    /// 定义约束类（User）
    /// </summary>
    public class UserMap : EntityTypeConfiguration<Model.User>
    {
        public UserMap()
        {
            // Primary Key
            this.HasKey(t => t.UserID);

            // Properties
            this.Property(t => t.UserName)
                .HasMaxLength(50);

            this.Property(t => t.Password)
                .HasMaxLength(100);

            // Table & Column Mappings
            this.ToTable("User");
            this.Property(t => t.UserID).HasColumnName("UserID");
            this.Property(t => t.UserName).HasColumnName("UserName");
            this.Property(t => t.Password).HasColumnName("Password");
            this.Property(t => t.IsValid).HasColumnName("IsValid");
        }
    }

    /// <summary>
    /// 定义约束类 （UserProfile）
    /// </summary>
    public class UserProfileMap : EntityTypeConfiguration<Model.UserProfile>
    {
        public UserProfileMap()
        {
            // Primary Key
            this.HasKey(t => t.UserID);

            // Properties
            this.Property(t => t.UserID)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

            this.Property(t => t.Name)
                .IsRequired()
                .HasMaxLength(50);

            this.Property(t => t.Email)
                .IsRequired()
                .HasMaxLength(100);

            this.Property(t => t.Telephone)
                .HasMaxLength(50);

            this.Property(t => t.Mobilephone)
                .HasMaxLength(20);

            this.Property(t => t.Address)
                .HasMaxLength(200);

            // Table & Column Mappings
            this.ToTable("UserProfile");
            this.Property(t => t.UserID).HasColumnName("UserID");
            this.Property(t => t.Name).HasColumnName("Name");
            this.Property(t => t.Sex).HasColumnName("Sex");
            this.Property(t => t.Birthday).HasColumnName("Birthday");
            this.Property(t => t.Email).HasColumnName("Email");
            this.Property(t => t.Telephone).HasColumnName("Telephone");
            this.Property(t => t.Mobilephone).HasColumnName("Mobilephone");
            this.Property(t => t.Address).HasColumnName("Address");
            this.Property(t => t.CreateDate).HasColumnName("CreateDate");

            // Relationships
            this.HasRequired(t => t.User)
                .WithRequiredDependent(t => t.UserProfile);
            //this.HasRequired(t => t.User).WithRequiredDependent(t => t.UserProfile);
            
        }
    }

    /// <summary>
    /// 定义约束类 （Manager）
    /// </summary>
    public class ManagerMap : EntityTypeConfiguration<Model.Manager>
    {
        public ManagerMap()
        {
            // Primary Key
            this.HasKey(t => t.UserID);

            // Properties
            this.Property(t => t.UserName)
                .HasMaxLength(50);

            this.Property(t => t.Password)
                .HasMaxLength(100);

            // Table & Column Mappings
            this.ToTable("User");
            this.Property(t => t.UserID).HasColumnName("UserID");
            this.Property(t => t.UserName).HasColumnName("UserName");
            this.Property(t => t.Password).HasColumnName("Password");
            this.Property(t => t.IsValid).HasColumnName("IsValid");
        }
    }

    /// <summary>
    /// 定义约束类 （Role）
    /// </summary>
    public class RoleMap : EntityTypeConfiguration<Model.Role>
    {
        public RoleMap()
        {
            // Primary Key
            this.HasKey(t => t.RoleID);

            // Properties
            this.Property(t => t.RoleName)
                .HasMaxLength(50);

            // Table & Column Mappings
            this.ToTable("Role");
            this.Property(t => t.RoleID).HasColumnName("RoleID");
            this.Property(t => t.RoleName).HasColumnName("RoleName");

            // Relationships
            this.HasMany(t => t.Users)
                .WithMany(t => t.Roles)
                .Map(m =>
                {
                    m.ToTable("UserRole");
                    m.MapLeftKey("RoleID");
                    m.MapRightKey("UserID");
                });
        }
    }

    /// <summary>
    /// 定义约束类 （Classify）
    /// </summary>
    public class ClassifyMap : EntityTypeConfiguration<Model.Classify>
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public ClassifyMap()
        {   // Primary Key
            this.HasKey(t => t.ClassifyID);
            // Properties
            this.Property(t => t.ClassifyName)
                .IsRequired()
                .HasMaxLength(50);
            // Table & Column Mappings
            this.ToTable("Category");
            this.Property(t => t.ClassifyID).HasColumnName("ClassifyID");
            this.Property(t => t.ClassifyNo).HasColumnName("ClassifyNo");
            this.Property(t => t.ClassifyName).HasColumnName("ClassifyName");
            this.Property(t => t.ParentID).HasColumnName("ParentID");
           
            // Relationships
            this.HasOptional(t => t.Parent)
                .WithMany(t => t.Children)
                .HasForeignKey(d => d.ParentID);
        }

    }

    #region CodeFirst配置数据表间约定
    /* public class ProdectMap : DbContext
     {


         //采用Fulend API方式配置
         protected override void OnModelCreating(DbModelBuilder modelBuilder)
         {


             //. Fluent API配置Configuration映射类
             modelBuilder.Configurations.Add(new ProdectMaps());

         }
     }

     public class ProdectMaps : EntityTypeConfiguration<Model.Product>
     {
         public ProdectMaps()
         {
             //将实体类 配置为数据库中的表名，并且指定其拥有者
             //base.OnModelCreating(modelBuilder);
             this.ToTable("Product", "dbo");

             //配置字段名、数据类型、长度、是否为空
             this.Property(t => t.ProductId).HasColumnName("ProductId");
             this.Property(t => t.ProductName).HasColumnName("ProductName").IsRequired().HasMaxLength(100);
             this.Property(t => t.Remark).HasColumnName("Remark");
             this.Property(t => t.UnitPrice).HasColumnName("UnitPrice");
             this.Property(t => t.CategoryID).HasColumnName("CategoryID");

             //为属性指定对应的SQL SERVER数据类型 (首先指定数据列，然后再次对该列在Sql server中的类型进行设置)
             this.Property(t => t.ProductId).HasColumnName("ProductId").HasColumnType("int");

             //设置sql server 中的text类型
             this.Property(t => t.Remark).HasColumnName("Remark").HasColumnType("text");

             //主键设置
             this.HasKey(t => t.ProductId);

             //特殊情况：一张表中有多个主键时  直接指向一个匿名对象
             this.HasKey(t => new { t.ProductId, t.ProductName });


             //数据库自动生成 字段值
             //数据库对于 int类型的主键数据 会自动生成自动增长值，但是有时候 不需要他自动增长
             //modelBuilder.Entity<Model.Product>().HasKey(t => t.ProductId);
             //modelBuilder.Entity<Model.Product>().Property(t => t.ProductId).HasColumnName("ProductId");
             this.Property(t => t.ProductId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);


             //设置 sql server数据库中 数据类型的长度、精度
             this.Property(t => t.UnitPrice).HasColumnName("UnitPrice");


             //设置非数据库字段属性:
             //在类中，如果有一些属性不需要映射到对应生成的数据表中，可以通过以下方式设置。
             this.Ignore(t => t.Remark);
         }
     }

     public class CategoryMaps : EntityTypeConfiguration<Model.Category>
     {
         public CategoryMaps()
         {
             this.ToTable("Category", "dbo");
             this.Property(c => c.CategoryID).HasColumnName("CategoryID");
             this.Property(c => c.CategoryName).HasColumnName("CategoryName");

         }
     }
     */
    #endregion


}
